package org.springblade.modules.admin.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.convert.NumberChineseFormatter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.tenant.annotation.TenantIgnore;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.admin.dto.feishu.FeiShuFieldsDTO;
import org.springblade.modules.admin.dto.plan.PlanContentExcelSearchDTO;
import org.springblade.modules.admin.entity.UserSignDetail;
import org.springblade.modules.admin.enums.SignStatusEnum;
import org.springblade.modules.admin.mapper.UserSignDetailMapper;
import org.springblade.modules.admin.service.UserSignDetailService;
import org.springblade.modules.admin.vo.HolidaysVo;
import org.springblade.modules.admin.vo.UserSignDetailPageVo;
import org.springblade.modules.admin.vo.feishu.LarkElevatorDailyAttendanceStaticVO;
import org.springblade.modules.admin.vo.feishu.LarkUserSignDetailVO;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

/**
 * 用户签到明细表 服务实现类
 */
@Service
@Slf4j
public class UserSignDetailServiceImpl extends BaseServiceImpl<UserSignDetailMapper, UserSignDetail> implements UserSignDetailService {

	@Resource
	private RedisTemplate<String, Object> redisTemplate;

	private final static String USER_SIGN_DATA = "user:sign:date:holidays";

	private static List<HolidaysVo> holidayList = new ArrayList<>(40);

	/**
	 * 1:迟到
	 * 2：早退
	 * 3：缺勤
	 * 4：范围外
	 */
	private static final Integer SIGN_TYPE[] = {0, 1, 2, 3, 4};

	@Override
	public IPage<UserSignDetailPageVo> listUserSignDetail(String startTime, String endTime, Integer signType, String types, IPage<UserSignDetailPageVo> page, String tenantId, String userName) {
		StringBuilder sb = new StringBuilder();
		if (signType != null && signType == 2 && StrUtil.isEmpty(types)) {
			//对应SIGN_TYPE
			types = "1, 2, 3, 4";
			signType = null;
		}
		if (StrUtil.isNotEmpty(types)) {
			signType = null;
		}
		if (StrUtil.isNotEmpty(types)) {
			String[] split = types.split(",");
			for (String type : split) {
				Integer integer = Convert.toInt(type);
				if (integer.equals(SIGN_TYPE[1])) {
					sb.append(" and t1.sign_be_late=0");
				} else if (integer.equals(SIGN_TYPE[2])) {
					sb.append(" and t1.sign_out_leave_early=0");
				} else if (integer.equals(SIGN_TYPE[3])) {
					sb.append(" and t1.sign_be_late=2 or t1.sign_out_leave_early=2 or t1.sign_be_late is null or t1.sign_out_leave_early is null");
				} else if (integer.equals(SIGN_TYPE[4])) {
					sb.append(" and t1.sign_type=2 or t1.sign_out_type=2");
				}
			}
		}

		String replace = sb.toString().replace("and", "or");
		String sql = replace.replaceFirst("or", " and (");
		if (StrUtil.isNotEmpty(sql.trim())) {
			sql = sql + " )";
		}
		return page.setRecords(baseMapper.listUserSignDetail(startTime, endTime, signType, sql, page, tenantId, userName));
	}

	@Override
	public void downExcelDetail(String startTime, String endTime, Integer signType, String types, List<List<String>> rows, String tenantId, String userName) {
		StringBuilder sb = new StringBuilder();
		if (signType != null && signType == 2 && StrUtil.isEmpty(types)) {
			//对应SIGN_TYPE
			types = "1, 2, 3, 4";
			signType = null;
		}
		if (StrUtil.isNotEmpty(types)) {
			signType = null;
		}
		if (StrUtil.isNotEmpty(types)) {
			String[] split = types.split(",");
			for (String type : split) {
				Integer integer = Convert.toInt(type);
				if (integer.equals(SIGN_TYPE[1])) {
					sb.append(" and t1.sign_be_late=0");
				} else if (integer.equals(SIGN_TYPE[2])) {
					sb.append(" and t1.sign_out_leave_early=0");
				} else if (integer.equals(SIGN_TYPE[3])) {
					sb.append(" and t1.sign_be_late=2 or t1.sign_out_leave_early=2 or t1.sign_be_late is null or t1.sign_out_leave_early is null");
				} else if (integer.equals(SIGN_TYPE[4])) {
					sb.append(" and t1.sign_type=2 or t1.sign_out_type=2");
				}
			}
		}
		String replace = sb.toString().replace("and", "or");
		String sql = replace.replaceFirst("or", " and (");
		if (StrUtil.isNotEmpty(sql.trim())) {
			sql = sql + " )";
		}
		List<UserSignDetailPageVo> voList = baseMapper.listUserSignDetail(startTime, endTime, signType, sql, null, tenantId, userName);
		voList.forEach(e -> {
			List<String> row = new ArrayList<>(9);
			row.add(Convert.toStr(e.getSignDate()));
			if (e.getWeek() == 7) {
				row.add(Convert.toStr("星期日"));
			} else {
				row.add(Convert.toStr("星期" + NumberChineseFormatter.format(Convert.toDouble(e.getWeek()), false, false)));
			}
			row.add(Convert.toStr(e.getHoliday() == 0 ? "工作日" : "休息日"));
			row.add(Convert.toStr(e.getUserName()));
			row.add(Convert.toStr(e.getGroupName()));
			row.add("维保");
			row.add(Convert.toStr(e.getSignTime()));
			row.add(Convert.toStr(e.getSignAddress()));
			if (e.getSignBeLate() != null && e.getSignBeLate() == SignStatusEnum.NORMAL.getId()) {
				if (e.getSignType() != null) {
					if (e.getSignType() == 2) {
						row.add("异常");
						row.add("范围外打卡");
					} else {
						row.add("正常");
						row.add("--");
					}
				} else {
					row.add("正常");
					row.add("--");
				}
				if (StrUtil.isEmpty(e.getNewSignDesc())) {
					row.add("--");
				} else {
					row.add(e.getNewSignDesc());
				}
			} else {
				row.add("异常");
				String i = "";
				if (e.getSignType() != null) {
					i = e.getSignType() == 2 ? "-范围外打卡" : "";
				}
				if (e.getSignBeLate() != null && e.getSignBeLate() == SignStatusEnum.BE_LATE.getId()) {
					row.add("迟到" + i);
				} else if (e.getSignBeLate() != null && e.getSignBeLate() == SignStatusEnum.ABSENTEEISM.getId()) {
					row.add("缺勤" + i);
				}
				if (StrUtil.isEmpty(e.getNewSignDesc())) {
					row.add("--");
				} else {
					row.add(e.getNewSignDesc());
				}
			}
			row.add(Convert.toStr(e.getSignOutTime()));
			row.add(Convert.toStr(e.getSignOutAddress()));
			if (e.getSignOutLeaveEarly() != null && e.getSignOutLeaveEarly() == SignStatusEnum.NORMAL.getId()) {
				if (e.getSignOutType() != null) {
					if (e.getSignOutType() == 2) {
						row.add("异常");
						row.add("范围外打卡");
					} else {
						row.add("正常");
						row.add("--");
					}
				} else {
					row.add("正常");
					row.add("--");
				}
				if (StrUtil.isEmpty(e.getNewSignOutDesc())) {
					row.add("--");
				} else {
					row.add(e.getNewSignOutDesc());
				}
			} else {
				row.add("异常");
				String i = "";
				if (e.getSignOutType() != null) {
					i = e.getSignOutType() == 2 ? "-范围外打卡" : "";
				}
				if (e.getSignOutLeaveEarly() != null && e.getSignOutLeaveEarly() == SignStatusEnum.BE_LATE.getId()) {
					row.add("早退" + i);
				} else if (e.getSignOutLeaveEarly() != null && e.getSignOutLeaveEarly() == SignStatusEnum.ABSENTEEISM.getId()) {
					row.add("缺勤" + i);
				}
				if (StrUtil.isEmpty(e.getNewSignOutDesc())) {
					row.add("--");
				} else {
					row.add(e.getNewSignOutDesc());
				}
			}
			rows.add(row);
		});
	}

	@Override
	public List<UserSignDetail> getList(PlanContentExcelSearchDTO planContentExcelSearchDTO) {
		planContentExcelSearchDTO.setStartTime(DateUtil.format(planContentExcelSearchDTO.getStartDate(), "yyyy-MM-dd HH:mm:ss"));
		planContentExcelSearchDTO.setEndTime(DateUtil.format(planContentExcelSearchDTO.getEndDate(), "yyyy-MM-dd HH:mm:ss"));

		return baseMapper.getList(planContentExcelSearchDTO);
	}


	/**
	 * 递归生成用户考勤信息
	 *
	 * @param signSettingId :考勤规则ID
	 * @param userId        :用户id
	 * @param groupId       组id
	 * @param beginDate     开始时间
	 * @param list          数据集
	 */
	private void userSignDetailInit(Long signSettingId, Long userId, Long groupId, Date beginDate, List<UserSignDetail> list, String tenantId) {

		Date endOfDay = DateUtil.endOfMonth(new Date());
		if (beginDate.getTime() <= endOfDay.getTime()) {
			String format = DateUtil.format(beginDate, "yyyyMMdd");
			Long signDate = Convert.toLong(format);
			UserSignDetail userSignDetail = new UserSignDetail();
			/*1表示是节假日不需要打开上班*/
			Integer signStatus = 1;
			Optional<HolidaysVo> optional = holidayList.stream().filter(o -> o.getMonthDay().equals(signDate.toString())).findFirst();
			if (optional.isPresent()) {
				HolidaysVo holidaysVo = optional.get();
				if (holidaysVo.getType().equals(signStatus.toString())) {
					userSignDetail.setSignStatus(signStatus);
					userSignDetail.setSignBeLate(signStatus);
					userSignDetail.setSignOutLeaveEarly(signStatus);
				}
			} else {
				int saturday = 7;
				int sunday = 1;
				int dayOfWeek = DateUtil.dayOfWeek(beginDate);
				if (dayOfWeek == saturday || dayOfWeek == sunday) {
					userSignDetail.setSignStatus(signStatus);
					userSignDetail.setSignBeLate(signStatus);
					userSignDetail.setSignOutLeaveEarly(signStatus);
				}
			}
			userSignDetail.setUserId(userId);
			userSignDetail.setSignDate(signDate);
			userSignDetail.setSignSettingId(signSettingId);
			userSignDetail.setGroupId(groupId);
			if (StrUtil.isNotEmpty(tenantId)) {
				userSignDetail.setTenantId(tenantId);
			}
			list.add(userSignDetail);
			userSignDetailInit(signSettingId, userId, groupId, DateUtil.offsetDay(beginDate, 1), list, tenantId);
		}
	}

	@Override
	public UserSignDetail getCurDateSign(Long userId) {
		return baseMapper.getCurDateSign(userId);
	}

	@Override
	@TenantIgnore
	public List<LarkUserSignDetailVO> getLarkSignDetailByCondition(String tenantId, Date startTime, Date endTime, Long userId) {
		// 所需参数校验
		if(Func.isNull(tenantId) || Func.isNull(startTime) || Func.isNull(endTime)){
			throw new ServiceException("所需参数不能为空");
		}
		return baseMapper.getLarkSignDetailByCondition(tenantId, startTime, endTime, userId);
	}

	@Override
	@TenantIgnore
	public List<LarkElevatorDailyAttendanceStaticVO> getLarkElevatorDailyAttendanceStatic() {
		return baseMapper.getLarkElevatorDailyAttendanceStatic();
	}

	@Override
	@TenantIgnore
	public List<LarkElevatorDailyAttendanceStaticVO> getLarkElevatorDailyAttendanceStaticFull() {
		return baseMapper.getLarkElevatorDailyAttendanceStaticFull();
	}

}
